package edu.math.chaos.itfunc.ui;

import edu.math.chaos.itfunc.AppProperties;
import edu.math.chaos.itfunc.alg.FractalBuilder;
import edu.math.chaos.itfunc.alg.TransformMatrix;
import edu.math.chaos.itfunc.api.Parameters;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.stage.Stage;

import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class ParametersController {

	@FXML
	private TextField iterations;
	@FXML
	private TextField width;
	@FXML
	private TextField height;
	@FXML
	private TextField initX;
	@FXML
	private TextField initY;
	@FXML
	private Label errorInfo;

	private Map<Parameters.ParameterType, TextField> paramsFieldsMap;

	@FXML
	public void initialize() {
		initParamsFieldsMap();
		prefill();
	}

	private void initParamsFieldsMap() {
		paramsFieldsMap = new LinkedHashMap<>();
		paramsFieldsMap.put(Parameters.ParameterType.ITERATION_THOUSANDS, iterations);
		paramsFieldsMap.put(Parameters.ParameterType.WIDTH, width);
		paramsFieldsMap.put(Parameters.ParameterType.HEIGHT, height);
		paramsFieldsMap.put(Parameters.ParameterType.INIT_X, initX);
		paramsFieldsMap.put(Parameters.ParameterType.INIT_Y, initY);
	}

	private void prefill() {
		iterations.setText(AppProperties.get(AppProperties.ITERATIONS));
		width.setText(AppProperties.get(AppProperties.WIDTH));
		height.setText(AppProperties.get(AppProperties.HEIGHT));
		initX.setText(AppProperties.get(AppProperties.INIT_X));
		initY.setText(AppProperties.get(AppProperties.INIT_Y));
	}

	@FXML
	private void build(ActionEvent event) {
		Parameters params = getParameters();
		if (params == null) {
			return;
		}

		try {
			double[][] coeffs = TransformMatrix.get(params);
			if (coeffs == null) {
				showError("Невозможно получить матрицу коэффициентов", null);
				return;
			}

			List<int[]> dots = new FractalBuilder().build(params, coeffs);

			showError("", null);
			hideParameters();

			BoardController.showBoard(dots, params);
		} catch (Throwable e) {
			showError("Произошла внутренняя ошибка", null);
			e.printStackTrace();
		}
	}

	private Parameters getParameters() {
		Parameters params = new Parameters();

		for (Map.Entry<Parameters.ParameterType, TextField> entry : paramsFieldsMap.entrySet()) {
			Parameters.ErrorInfo error = entry.getKey().setParameter(entry.getValue().getText(), params);
			if (error != null) {
				showError(error.getMessage(), entry.getValue());
				return null;
			}
		}

		Parameters.ErrorInfo error = params.checkParameters();
		if (error != null) {
			showError(error.getMessage(), paramsFieldsMap.get(error.getParameterType()));
			return null;
		}

		return params;
	}

	private void showError(String message, TextField textField) {
		errorInfo.setText(message);
		focusAndSelect(textField);
	}

	private void focusAndSelect(TextField textField) {
		if (textField == null) {
			return;
		}

		textField.requestFocus();
		textField.selectAll();
	}

	private static final String FXML_PATH = "Parameters.fxml";
	private static final String TITLE = UIApplication.makeStageTitle("Параметры");

	private static Stage stage;

	public static void openParameters(Stage stage) throws IOException {
		Parent root = FXMLLoader.load(ParametersController.class.getResource(FXML_PATH));
		stage.setTitle(TITLE);
		stage.setScene(new Scene(root, 300, 210));
		stage.setResizable(false);
		stage.show();
		ParametersController.stage = stage;
	}

	public static void showParameters() {
		if (stage == null) {
			return;
		}

		stage.show();
	}

	public static void hideParameters() {
		if (stage == null) {
			return;
		}

		stage.hide();
	}
}